package com.cn.delan.core.encrypt;

import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.*;
import java.util.UUID;

import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JDialog;
import javax.swing.JFileChooser;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTextField;
/**
 *这是一个进行BASE64编码解码的类<br>
 *其中提供静态方法进行标准编码、解码和变异编码、解码。效率为182M大小的文件需要10秒左右进行编码、解码。
 *@author 	BingGo
 *@version 1.6 2009/11/26
 **/
public class Base64
{
	 //初始化GUI
	 private static final JDialog loadDialog = new JDialog();
	 private static final JLabel offsetLabel = new JLabel("变异值");
	 private static final JTextField offsetText = new JTextField("0",3);
	 private static final JCheckBox isEncode = new JCheckBox("Base64编码",true);
	 private static final JPanel textPanel = new JPanel(new FlowLayout(FlowLayout.CENTER,10,0));
	 private static final JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT,10,0));
	 private static final JFileChooser inFileChooser = new JFileChooser();
	 private static final JFileChooser outFileChooser = new JFileChooser();
	 private static final JButton okButton = new JButton("打开");
	 private static final JButton cancelButton = new JButton("关闭");
	 private static File currentDirectory;
	 //初始化GUI
	 static
		 {Base64.okButton.addActionListener(
				  new ActionListener()
					  {public void actionPerformed(ActionEvent e)
						  	{int offset = 0;
						  	 boolean isEncode = true;
						  	 File inFile = null;
						  	 File outFile = null;
						  	 isEncode = Base64.isEncode.isSelected();
						  	 try
						  	 	{offset = Integer.parseInt(Base64.offsetText.getText());
						  	 	}
						  	 catch(NumberFormatException formatE)
						  	 	{JOptionPane.showMessageDialog(Base64.loadDialog,"必须输入变异值，且只能为半角数字！","输入格式错误！",JOptionPane.ERROR_MESSAGE);
						  	 	 return;
						  	 	}
						  	 if(offset<0 || offset>63)
						  	 	{JOptionPane.showMessageDialog(Base64.loadDialog,"您所输入的变异值，必须在0到63之间！","数值范围错误！",JOptionPane.ERROR_MESSAGE);
						  		 return;
						  	 	}
						  	 inFile = Base64.inFileChooser.getSelectedFile();
						  	 if(inFile==null)
						  		{JOptionPane.showMessageDialog(Base64.loadDialog,"请选择要操作的文件或文件夹！","没有指定文件！",JOptionPane.ERROR_MESSAGE);
						  		 return;
						  		}
						  	 Base64.currentDirectory = Base64.inFileChooser.getCurrentDirectory();
						  	 Base64.outFileChooser.setCurrentDirectory(Base64.currentDirectory);
					  	 	 Base64.loadDialog.dispose();
						  	 if(Base64.outFileChooser.showSaveDialog(null)==JFileChooser.APPROVE_OPTION)
						  	 	{outFile = Base64.outFileChooser.getSelectedFile();
						  	 	 try
						  	 	 	{if(isEncode)
						  	 	 		{if(offset==0)
						  	 	 			Base64.encode(inFile, outFile);
						  	 	 		 else
						  	 	 			Base64.encode(inFile, outFile, offset);
						  	 	 		}
						  	 	 	 else
						  	 	 	 	{if(offset==0)
						  	 	 			Base64.decode(inFile, outFile);
						  	 	 		 else
						  	 	 			Base64.decode(inFile, outFile, offset);
						  	 	 	 	}
						  	 	 	}
						  	 	 catch(IOException IOE)
						  	 	 	{JOptionPane.showMessageDialog(Base64.loadDialog,"请查看用户是否有写文件权限！","产生文件错！",JOptionPane.ERROR_MESSAGE);
						  	 	 	}
						  	 	}
					  		  Base64.currentDirectory = Base64.outFileChooser.getCurrentDirectory();
					  		  Base64.inFileChooser.setCurrentDirectory(Base64.currentDirectory);
					  		 }
					  }
				 );
		  Base64.cancelButton.addActionListener(
				  new ActionListener()
				  {public void actionPerformed(ActionEvent e)
				  	{loadDialog.dispose();
				  	}
				  }
				 );
		  Base64.inFileChooser.setControlButtonsAreShown(false);
		  Base64.outFileChooser.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES);
		  Base64.inFileChooser.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES);
		  if(Base64.currentDirectory!=null)
			  Base64.inFileChooser.setCurrentDirectory(Base64.currentDirectory);
		  Base64.loadDialog.setTitle("请选择要进行Base64编码或解码的文件或文件夹");
		  Base64.loadDialog.setLayout(new FlowLayout(FlowLayout.RIGHT,0,10));
		  Base64.textPanel.add(Base64.isEncode);
		  Base64.textPanel.add(Base64.offsetLabel);
		  Base64.textPanel.add(Base64.offsetText);
		  Base64.buttonPanel.add(Base64.okButton);
		  Base64.buttonPanel.add(Base64.cancelButton);
		  Base64.loadDialog.add(Base64.textPanel);
		  Base64.loadDialog.add(Base64.inFileChooser);
		  Base64.loadDialog.add(Base64.buttonPanel);
		  Base64.loadDialog.setSize(510,470);
		  Base64.loadDialog.setResizable(false);	 
		 }
/**
 *BASE64编码解码表
 **/
 private static final byte [] encodeDict = {'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z','a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z','0','1','2','3','4','5','6','7','8','9','+','/'};
 private static final byte [] decodeDict = new byte[256];
 private static final int tempFileLength = 1048576;
 static
 {for(int i=0;i<decodeDict.length;i++)
	 decodeDict[i]=64;
  decodeDict[65]=0;
  decodeDict[66]=1;
  decodeDict[67]=2;
  decodeDict[68]=3;
  decodeDict[69]=4;
  decodeDict[70]=5;
  decodeDict[71]=6;
  decodeDict[72]=7;
  decodeDict[73]=8;
  decodeDict[74]=9;
  decodeDict[75]=10;
  decodeDict[76]=11;
  decodeDict[77]=12;
  decodeDict[78]=13;
  decodeDict[79]=14;
  decodeDict[80]=15;
  decodeDict[81]=16;
  decodeDict[82]=17;
  decodeDict[83]=18;
  decodeDict[84]=19;
  decodeDict[85]=20;
  decodeDict[86]=21;
  decodeDict[87]=22;
  decodeDict[88]=23;
  decodeDict[89]=24;
  decodeDict[90]=25;
  
  decodeDict[97]=26;
  decodeDict[98]=27;
  decodeDict[99]=28;
  decodeDict[100]=29;
  decodeDict[101]=30;
  decodeDict[102]=31;
  decodeDict[103]=32;
  decodeDict[104]=33;
  decodeDict[105]=34;
  decodeDict[106]=35;
  decodeDict[107]=36;
  decodeDict[108]=37;
  decodeDict[109]=38;
  decodeDict[110]=39;
  decodeDict[111]=40;
  decodeDict[112]=41;
  decodeDict[113]=42;
  decodeDict[114]=43;
  decodeDict[115]=44;
  decodeDict[116]=45;
  decodeDict[117]=46;
  decodeDict[118]=47;
  decodeDict[119]=48;
  decodeDict[120]=49;
  decodeDict[121]=50;
  decodeDict[122]=51;

  decodeDict[48]=52;
  decodeDict[49]=53;
  decodeDict[50]=54;
  decodeDict[51]=55;
  decodeDict[52]=56;
  decodeDict[53]=57;
  decodeDict[54]=58;
  decodeDict[55]=59;
  decodeDict[56]=60;
  decodeDict[57]=61;

  decodeDict[43]=62;
  decodeDict[47]=63;
 }
/**
 *将指定字符串编码后返回。
 *@param message 是要进行编码的字符串。
 *@return 返回已经编码的字节数组。
 **/ 
 public static byte[] encode(String message)
	{return Base64.encode(message.getBytes());
	}
 /**
  *将指定字符串编码后返回。
  *@param message 是要进行编码的字符串。
  *@param offset 字典偏移量,当此参数为0时是标准Base64加密，否则将其与64取模所得的值作为字典的起点。进行变异加密。
  *@return 返回已经编码的字节数组。
  **/ 
  public static byte[] encode(String message,int offset)
 	{return Base64.encode(message.getBytes(),offset);
 	}
 /**
  *将指定字节数组编码后返回。
  *@param messageByte 是要进行编码的字节数组。
  *@return 返回已经编码的字节数组。
  **/ 
  public static byte[] encode(byte [] messageByte)
  	{int messageLength = messageByte.length;
  	 int currentLength = messageLength;
  	 int encodedLength = messageLength/3;
  	 int mod = messageLength%3;
  	 int count = 0;
  	 if(mod!=0)
  	 	encodedLength++;
  	 encodedLength = encodedLength*4;
  	 byte [] encodedByte = new byte[encodedLength];
  	 byte [] tempByte = new byte[3];
  	 while(currentLength>0)
  	 	{int start = count++*4;
  	 	 int endModal = 0;
  	 	 tempByte[0] = messageByte[messageLength-currentLength--];
  	 	 /*
  	 	 //对这两个判断进行优化。合二为一。
  	 	 if(currentLength>0)
  	 	 	tempByte[1] = message[messageLength-currentLength--];
  	 	 else
  	 	 	{tempByte[1] = 0;
  	 	 	}
  	 	 if(currentLength>0)
  	 	 	tempByte[2] = message[messageLength-currentLength--];
  	 	 else
  	 	 	{tempByte[2] = 0;
  	 	 	 //mod为1时endModal为2，mod为2时endModal为1，公式
  	 	 	 endModal = 1 - currentLength--;
  	 	 	}
  	 	 */
  	 	 
  	 	 if(currentLength>1)
  	 	 	{tempByte[1] = messageByte[messageLength-currentLength--];
  	 	 	 tempByte[2] = messageByte[messageLength-currentLength--];
  	 	 	}
  	 	 else
  	 	 if(currentLength==1)
  	 	 	{tempByte[1] = messageByte[messageLength-currentLength--];
  	 	 	 tempByte[2] = 0;
  	 	 	 endModal = 1;
  	 	 	}
  	 	 else
  	 	 if(currentLength<1)
  	 	 	{tempByte[1] = 0;
  	 	 	 tempByte[2] = 0;
  	 	 	 endModal = 2;
  	 	 	}
  	 	 
  	 	 //System.out.println((temp[0]&255)+":"+((~temp[0])+1));
  	 	 //需要与操作否则可能为负
  	 	 encodedByte[start] = encodeDict[(tempByte[0]&252)>>2];
  	 	 encodedByte[start+1] = encodeDict[((tempByte[0]&3)<<4)+((tempByte[1]&240)>>4)];
  	 	 encodedByte[start+2] = encodeDict[((tempByte[1]&15)<<2)+((tempByte[2]&192)>>6)];
  	 	 encodedByte[start+3] = encodeDict[tempByte[2]&63];
  	 	 if(endModal == 2)
  	 	 	{encodedByte[start+2] = '=';
  	 	 	 encodedByte[start+3] = '=';
  	 	 	}
  	 	 if(endModal == 1)
  	 	 	encodedByte[start+3] = '=';
  	 	}
  	 return encodedByte;
  	}
  /**
   *将指定字节数组编码后返回。
   *@param messageByte 是要进行编码的字节数组。
   *@param offset 字典偏移量,当此参数为0时是标准Base64加密，否则将其与64取模所得的值作为字典的起点。进行变异加密。
   *@return 返回已经编码的字符串。
   **/ 
   public static byte[] encode(byte [] messageByte,int offset)
   	{if(offset==0)
   		return Base64.encode(messageByte);
	 int messageLength = messageByte.length;
   	 int currentLength = messageLength;
   	 int encodedLength = messageLength/3;
   	 int mod = messageLength%3;
   	 int currentOffset = offset%64;
   	 int count = 0;
   	 if(mod!=0)
   	 	encodedLength++;
   	 encodedLength = encodedLength*4;
   	 byte [] encodedByte = new byte[encodedLength];
   	 byte [] tempByte = new byte[3];
   	 while(currentLength>0)
   	 	{int start = count++*4;
   	 	 int endModal = 0;
   	 	 tempByte[0] = messageByte[messageLength-currentLength--];
   	 	 
   	 	 if(currentLength>1)
   	 	 	{tempByte[1] = messageByte[messageLength-currentLength--];
   	 	 	 tempByte[2] = messageByte[messageLength-currentLength--];
   	 	 	}
   	 	 else
   	 	 if(currentLength==1)
   	 	 	{tempByte[1] = messageByte[messageLength-currentLength--];
   	 	 	 tempByte[2] = 0;
   	 	 	 endModal = 1;
   	 	 	}
   	 	 else
   	 	 if(currentLength<1)
   	 	 	{tempByte[1] = 0;
   	 	 	 tempByte[2] = 0;
   	 	 	 endModal = 2;
   	 	 	}
   	 	 
   	 	 int decodeIndex1 = ((tempByte[0]&252)>>2)+currentOffset;
   	 	 int decodeIndex2 = (((tempByte[0]&3)<<4)+((tempByte[1]&240)>>4))+currentOffset;
   	 	 int decodeIndex3 = (((tempByte[1]&15)<<2)+((tempByte[2]&192)>>6))+currentOffset;
   	 	 int decodeIndex4 = (tempByte[2]&63)+currentOffset;
   	 	 decodeIndex1=decodeIndex1>63?decodeIndex1-64:decodeIndex1;
   	 	 decodeIndex2=decodeIndex2>63?decodeIndex2-64:decodeIndex2;
   	 	 decodeIndex3=decodeIndex3>63?decodeIndex3-64:decodeIndex3;
   	 	 decodeIndex4=decodeIndex4>63?decodeIndex4-64:decodeIndex4;
   	 	 encodedByte[start] = encodeDict[decodeIndex1];
   	 	 encodedByte[start+1] = encodeDict[decodeIndex2];
   	 	 encodedByte[start+2] = encodeDict[decodeIndex3];
   	 	 encodedByte[start+3] = encodeDict[decodeIndex4];
   	 	 if(endModal == 2)
   	 	 	{encodedByte[start+2] = '=';
   	 	 	 encodedByte[start+3] = '=';
   	 	 	}
   	 	 if(endModal == 1)
   	 	 	encodedByte[start+3] = '=';
   	 	}
   	 return encodedByte;
   	}
 /**
  *将一个输入流进行编码.适用于所有文件，通过流的available()方法获取流大小大于1M的采用硬盘缓存形式，否则用内存缓存。<br/>
  *文件流自动识别测试通过，其他流没有经过测试。
  *@param inputStream 是要进行编码的输入流。
  *@return 返回编码后的输入流。
  **/
 public static InputStream encode(InputStream inputStream) throws IOException
 	{InputStream encodedInputStream = null;
	 if(inputStream.available()>tempFileLength)
		 encodedInputStream = Base64.encodeByTempFile(inputStream);
	 else
		 encodedInputStream = Base64.encodeByMemory(inputStream);
 	 return encodedInputStream;
 	}
 /**
  *将一个输入流进行编码.适用于所有文件，通过流的available()方法获取流大小大于1M的采用硬盘缓存形式，否则用内存缓存。<br/>
  *文件流自动识别测试通过，其他流没有经过测试。
  *@param inputStream 是要进行编码的输入流。
  *@param offset 字典偏移量,当此参数为0时是标准Base64加密，否则将其与64取模所得的值作为字典的起点。进行变异加密。
  *@return 返回编码后的输入流。
  **/
 public static InputStream encode(InputStream inputStream,int offset) throws IOException
 	{InputStream encodedInputStream = null;
	 if(inputStream.available()>tempFileLength)
		 encodedInputStream = Base64.encodeByTempFile(inputStream,offset);
	 else
		 encodedInputStream = Base64.encodeByMemory(inputStream,offset);
 	 return encodedInputStream;
 	}
 /**
  *将一个输入流进行编码.只适用于小文件，大文件消耗内存资源太厉害容易引起JVM崩溃。但由于使用内存作为缓存效率较高。
  *@param inputStream 是要进行编码的输入流。
  *@return 返回编码后的输入流。
  **/
 private static InputStream encodeByMemory(InputStream inputStream) throws IOException
 	{ByteArrayOutputStream outputStreamToMemory = new ByteArrayOutputStream();
 	 int length = -1;
 	 byte [] content = new byte[3000];
 	 while((length=inputStream.read(content))!=-1)
 	 	outputStreamToMemory.write(content,0,length);
 	 content = outputStreamToMemory.toByteArray();
 	 content = Base64.encode(content);
 	 ByteArrayInputStream inputStreamFromMemory = new ByteArrayInputStream(content);
 	 System.gc();
 	 return inputStreamFromMemory;
 	}
 /**
  *将一个输入流进行编码.只适用于小文件，大文件消耗内存资源太厉害容易引起JVM崩溃。但由于使用内存作为缓存效率较高。
  *@param inputStream 是要进行编码的输入流。
   *@param offset 字典偏移量,当此参数为0时是标准Base64加密，否则将其与64取模所得的值作为字典的起点。进行变异加密。
  *@return 返回编码后的输入流。
  **/
 private static InputStream encodeByMemory(InputStream inputStream,int offset) throws IOException
 	{ByteArrayOutputStream outputStreamToMemory = new ByteArrayOutputStream();
 	 int length = -1;
 	 byte [] content = new byte[3000];
 	 while((length=inputStream.read(content))!=-1)
 	 	outputStreamToMemory.write(content,0,length);
 	 content = outputStreamToMemory.toByteArray();
 	 content = Base64.encode(content,offset);
 	 ByteArrayInputStream inputStreamFromMemory = new ByteArrayInputStream(content);
 	 System.gc();
 	 return inputStreamFromMemory;
 	}
 /**
  *将一个输入流进行编码.适用于大文件，但由于使用硬盘作为缓存效率较低。
  *@param inputStream 是要进行编码的输入流。
  *@return 返回编码后的输入流。
  **/
 private static InputStream encodeByTempFile(InputStream inputStream) throws IOException
 	{byte []content = new byte[3000];
 	 FileInputStream inputStreamFromTempFile = null;
 	 int length = -1;
 	 File tempFile = File.createTempFile(UUID.randomUUID().toString(), null);
 	 FileOutputStream outputStreamToTempFile = new FileOutputStream(tempFile);
 	 while((length=inputStream.read(content))!=-1)
 		 {byte []encodedContent = null;
 		  if(length==3000)
 			 encodedContent = Base64.encode(content);
 		  else
 			 {byte temp[] = new byte[length];
 			  for(int i=0;i<length;i++)
 				  temp[i] = content[i];
 			  encodedContent = Base64.encode(temp);
 			 }
 		  outputStreamToTempFile.write(encodedContent, 0, encodedContent.length);
 		  outputStreamToTempFile.flush();
 		 }
 	 outputStreamToTempFile.close();
 	 inputStreamFromTempFile = new FileInputStream(tempFile);
	 System.gc();
 	 return inputStreamFromTempFile;
 	}
 /**
  *将一个输入流进行编码.适用于大文件，但由于使用硬盘作为缓存效率较低。
  *@param inputStream 是要进行编码的输入流。
  *@param offset 字典偏移量,当此参数为0时是标准Base64加密，否则将其与64取模所得的值作为字典的起点。进行变异加密。
  *@return 返回编码后的输入流。
  **/
 private static InputStream encodeByTempFile(InputStream inputStream,int offset) throws IOException
 	{byte []content = new byte[3000];
 	 FileInputStream inputStreamFromTempFile = null;
 	 int length = -1;
 	 File tempFile = File.createTempFile(UUID.randomUUID().toString(), null);
 	 FileOutputStream outputStreamToTempFile = new FileOutputStream(tempFile);
 	 while((length=inputStream.read(content))!=-1)
 		 {byte []encodedContent = null;
 		  if(length==3000)
 			 encodedContent = Base64.encode(content,offset);
 		  else
 			 {byte temp[] = new byte[length];
 			  for(int i=0;i<length;i++)
 				  temp[i] = content[i];
 			  encodedContent = Base64.encode(temp,offset);
 			 }
 		  outputStreamToTempFile.write(encodedContent, 0, encodedContent.length);
 		  outputStreamToTempFile.flush();
 		 }
 	 outputStreamToTempFile.close();
 	 inputStreamFromTempFile = new FileInputStream(tempFile);
	 System.gc();
 	 return inputStreamFromTempFile;
 	}
 /**
  * 将一个输入流进行编码.适用于大文件，但由于使用硬盘作为缓存效率较低，不过比encodeByTempFile(InputStream)效率高。
  * @param inFile 是要进行编码的输入文件对象。
  * @param outFile 是进行编码后的输出文件对象。
  * @throws IOException 编码产生错误时抛出此异常。
  */
 private static void encodeToFile(File inFile,File outFile) throws IOException
 	{if(!inFile.isFile())
 		return;
	 if(outFile.getParentFile()!=null && !outFile.getParentFile().exists() && !outFile.getParentFile().mkdirs())
		return;
	 byte []content = new byte[3000];
 	 FileInputStream inputStream = new FileInputStream(inFile);
 	 int length = -1;
 	 FileOutputStream outputStreamToFile = new FileOutputStream(outFile);
 	 while((length=inputStream.read(content))!=-1)
 		 {byte []encodedContent = null;
 		  if(length==3000)
 			 encodedContent = Base64.encode(content);
 		  else
 			 {byte temp[] = new byte[length];
 			  for(int i=0;i<length;i++)
 				  temp[i] = content[i];
 			  encodedContent = Base64.encode(temp);
 			 }
 		  outputStreamToFile.write(encodedContent, 0, encodedContent.length);
 		  outputStreamToFile.flush();
 		 }
 	 outputStreamToFile.close();
 	 inputStream.close();
 	}
 /**
  * 将一个输入流进行编码.适用于大文件，但由于使用硬盘作为缓存效率较低，不过比encodeByTempFile(InputStream,int)效率高。
  * @param inFile 是要进行编码的输入文件对象。
  * @param outFile 是进行编码后的输出文件对象。
  * @param offset 字典偏移量,当此参数为0时是标准Base64加密，否则将其与64取模所得的值作为字典的起点。进行变异加密。
  * @throws IOException 编码产生错误时抛出此异常。
  */
 private static void encodeToFile(File inFile,File outFile,int offset) throws IOException
 	{if(!inFile.isFile())
 		return;
	 if(outFile.getParentFile()!=null && !outFile.getParentFile().exists() && !outFile.getParentFile().mkdirs())
		return;
	 byte []content = new byte[3000];
 	 FileInputStream inputStream = new FileInputStream(inFile);
 	 int length = -1;
 	 FileOutputStream outputStreamToFile = new FileOutputStream(outFile);
 	 while((length=inputStream.read(content))!=-1)
 		 {byte []encodedContent = null;
 		  if(length==3000)
 			 encodedContent = Base64.encode(content,offset);
 		  else
 			 {byte temp[] = new byte[length];
 			  for(int i=0;i<length;i++)
 				  temp[i] = content[i];
 			  encodedContent = Base64.encode(temp,offset);
 			 }
 		  outputStreamToFile.write(encodedContent, 0, encodedContent.length);
 		  outputStreamToFile.flush();
 		 }
 	 outputStreamToFile.close();
 	 inputStream.close();
 	}
 /**
  *将一个输入流进行编码.适用于所有文件，通过流的available()方法获取流大小大于1M的采用硬盘缓存形式，否则用内存缓存。<br/>
  *文件流自动识别测试通过，其他流没有经过测试。
  *@param inFileInputStream 是要进行编码的输入流。
  *@param outFileOutputStream 是进行编码后的输出流。
  **/
 public static void encode(InputStream inFileInputStream,OutputStream outFileOutputStream) throws IOException
 	{InputStream encodedInputStream = Base64.encode(inFileInputStream);
 	 byte [] temp = new byte[5000];
 	 int length = -1;
 	 if(encodedInputStream==null)
 		 return;
	 while((length=encodedInputStream.read(temp))!=-1)
	 	{outFileOutputStream.write(temp,0,length);
	 	}
	 outFileOutputStream.flush();
	 System.gc();
 	}
 /**
  *将一个输入文件进行编码.适用于所有文件，通过流的available()方法获取流大小大于1M的采用硬盘缓存形式，否则用内存缓存。<br/>
  *文件流自动识别测试通过，其他流没有经过测试。
  *@param inFile 是要进行编码的输入文件对象。
  *@param outFile 是进行编码后的输出文件对象。
  **/
 public static void encode(File inFile,File outFile) throws IOException
 	{if(!inFile.exists())
	 	return;
	 if(inFile.isFile())
		 Base64.encodeFromFile(inFile, outFile);
	 else
		 Base64.encodeFromDirectory(inFile, outFile); 
 	}
 /**
  *将一个输入文件进行编码.适用于所有文件，通过流的available()方法获取流大小大于1M的采用硬盘缓存形式，否则用内存缓存。<br/>
  *文件流自动识别测试通过，其他流没有经过测试。
  *@param inFileName 是要进行编码的输入文件路经。
  *@param outFileName 是进行编码后的输出文件路经。
  **/
 public static void encode(String inFileName,String outFileName) throws IOException
 	{File inFile = new File(inFileName);
 	 File outFile = new File(outFileName);
 	 Base64.encode(inFile,outFile);
 	}
 /**
  *将一个输入文件进行编码.适用于所有文件，通过流的available()方法获取流大小大于1M的采用硬盘缓存形式，否则用内存缓存。<br/>
  *文件流自动识别测试通过，其他流没有经过测试。
  *@param inFile 是要进行编码的输入文件对象。
  *@param outFile 是进行编码后的输出文件对象。
  **/
 private static void encodeFromFile(File inFile,File outFile) throws IOException
 	{if(!inFile.isFile())
 		return;
	 if(outFile.getParentFile()!=null && !outFile.getParentFile().exists() && !outFile.getParentFile().mkdirs())
		return;
	 Base64.encodeToFile(inFile, outFile);
	 /*
	 FileInputStream inFileInputStream = new FileInputStream(inFile);
 	 FileOutputStream outFileOutputStream = new FileOutputStream(outFile);
	 Base64.encode(inFileInputStream, outFileOutputStream);
	 inFileInputStream.close();
	 outFileOutputStream.close();
	 */
 	}
 /**
  *将一个输入文件夹进行编码.适用于所有文件，通过流的available()方法获取流大小大于1M的采用硬盘缓存形式，否则用内存缓存。<br/>
  *文件流自动识别测试通过，其他流没有经过测试。
  *@param inFile 是要进行编码的输入文件夹对象。
  *@param outFile 是进行编码后的输出文件夹对象。
  **/
 private static void encodeFromDirectory(File inFile,File outFile) throws IOException
 	{if(!inFile.isDirectory())
 		return;
	 if(!outFile.exists())
	 	{if(!outFile.mkdirs())
	 		return;
	 	}
	 else
	 if(!outFile.isDirectory())
		return;
	 for(File currentFile:inFile.listFiles())
		{File outDirectory = new File(outFile,currentFile.getName());
		 if(currentFile.isDirectory())
			{if(outDirectory.mkdirs())
				 Base64.encodeFromDirectory(currentFile, outDirectory);
			}
		 else
			{try
			 	{Base64.encodeFromFile(currentFile, outDirectory);
			 	}
			 catch(IOException e)
			 	{if(outDirectory.exists())
 			 		outDirectory.delete();
				 System.err.println("Base64.encode "+currentFile.getAbsolutePath()+" to "+outDirectory.getAbsolutePath()+" error!\n"+e.getMessage());
			 	}
			}
		}
 	}
 /**
  *将一个输入流进行编码.适用于所有文件，通过流的available()方法获取流大小大于1M的采用硬盘缓存形式，否则用内存缓存。<br/>
  *文件流自动识别测试通过，其他流没有经过测试。
  *@param inFileInputStream 是要进行编码的输入流。
  *@param outFileOutputStream 是进行编码后的输出流。
  *@param offset 字典偏移量,当此参数为0时是标准Base64加密，否则将其与64取模所得的值作为字典的起点。进行变异加密。
  **/
 public static void encode(InputStream inFileInputStream,OutputStream outFileOutputStream,int offset) throws IOException
 	{InputStream encodedInputStream = Base64.encode(inFileInputStream,offset);
 	 byte [] temp = new byte[5000];
 	 int length = -1;
 	 if(encodedInputStream==null)
 		 return;
	 while((length=encodedInputStream.read(temp))!=-1)
	 	{outFileOutputStream.write(temp,0,length);
	 	}
	 outFileOutputStream.flush();
	 System.gc();
 	}
 /**
  *将一个输入文件进行编码.适用于所有文件，通过流的available()方法获取流大小大于1M的采用硬盘缓存形式，否则用内存缓存。<br/>
  *文件流自动识别测试通过，其他流没有经过测试。
  *@param inFile 是要进行编码的输入文件对象。
  *@param outFile 是进行编码后的输出文件对象。
  *@param offset 字典偏移量,当此参数为0时是标准Base64加密，否则将其与64取模所得的值作为字典的起点。进行变异加密。
  **/
 public static void encode(File inFile,File outFile,int offset) throws IOException
 	{if(!inFile.exists())
	 	return;
	 if(inFile.isFile())
		 Base64.encodeFromFile(inFile, outFile, offset);
	 else
		 Base64.encodeFromDirectory(inFile, outFile, offset); 
 	}
 /**
  *将一个输入文件进行编码.适用于所有文件，通过流的available()方法获取流大小大于1M的采用硬盘缓存形式，否则用内存缓存。<br/>
  *文件流自动识别测试通过，其他流没有经过测试。
  *@param inFileName 是要进行编码的输入文件路经。
  *@param outFileName 是进行编码后的输出文件路经。
  *@param offset 字典偏移量,当此参数为0时是标准Base64加密，否则将其与64取模所得的值作为字典的起点。进行变异加密。
  **/
 public static void encode(String inFileName,String outFileName,int offset) throws IOException
 	{File inFile = new File(inFileName);
 	 File outFile = new File(outFileName);
 	 Base64.encode(inFile,outFile,offset);
 	}
 /**
  *将一个输入文件进行编码.适用于所有文件，通过流的available()方法获取流大小大于1M的采用硬盘缓存形式，否则用内存缓存。<br/>
  *文件流自动识别测试通过，其他流没有经过测试。
  *@param inFile 是要进行编码的输入文件对象。
  *@param outFile 是进行编码后的输出文件对象。
  *@param offset 字典偏移量,当此参数为0时是标准Base64加密，否则将其与64取模所得的值作为字典的起点。进行变异加密。
  **/
 private static void encodeFromFile(File inFile,File outFile,int offset) throws IOException
 	{if(!inFile.isFile())
 		return;
	 if(!outFile.getParentFile().exists() && !outFile.getParentFile().mkdirs())
		return;
	 Base64.encodeToFile(inFile, outFile, offset);
	 /*
	 FileInputStream inFileInputStream = new FileInputStream(inFile);
 	 FileOutputStream outFileOutputStream = new FileOutputStream(outFile);
	 Base64.encode(inFileInputStream, outFileOutputStream,offset);
	 inFileInputStream.close();
	 outFileOutputStream.close();
	 */
 	}
 /**
  *将一个输入文件夹进行编码.适用于所有文件，通过流的available()方法获取流大小大于1M的采用硬盘缓存形式，否则用内存缓存。<br/>
  *文件流自动识别测试通过，其他流没有经过测试。
  *@param inFile 是要进行编码的输入文件夹对象。
  *@param outFile 是进行编码后的输出文件夹对象。
  *@param offset 字典偏移量,当此参数为0时是标准Base64加密，否则将其与64取模所得的值作为字典的起点。进行变异加密。
  **/
 private static void encodeFromDirectory(File inFile,File outFile,int offset) throws IOException
 	{if(!inFile.isDirectory())
 		return;
	 if(!outFile.exists())
	 	{if(!outFile.mkdirs())
	 		return;
	 	}
	 else
	 if(!outFile.isDirectory())
		return;
	 for(File currentFile:inFile.listFiles())
		{File outDirectory = new File(outFile,currentFile.getName());
		 if(currentFile.isDirectory())
			{if(outDirectory.mkdirs())
				 Base64.encodeFromDirectory(currentFile, outDirectory, offset);
			}
		 else
			{try
			 	{Base64.encodeFromFile(currentFile, outDirectory, offset);
			 	}
			 catch(IOException e)
			 	{if(outDirectory.exists())
 			 		outDirectory.delete();
				 System.err.println("Base64.encode "+currentFile.getAbsolutePath()+" to "+outDirectory.getAbsolutePath()+" error!\n"+e.getMessage());
			 	}
			}
		}
 	}
 /**
 *将指定字符串解码后返回。
 *@param message 是要进行解码的字符串。
 *@return 返回已经解码的字节数组。
 **/ 
 public static byte [] decode(String message) throws IOException
 	{String messageInALine = message;
 	 messageInALine = messageInALine.replaceAll("\r\n","");
 	 byte [] decodeByte = Base64.decode(messageInALine.getBytes());
 	 return decodeByte;
 	}
 /**
  *将指定字符串解码后返回。
  *@param message 是要进行解码的字符串。
   *@param offset 字典偏移量,当此参数为0时是标准Base64解密，否则将其与64取模所得的值作为字典的起点。进行变异解密。
  *@return 返回已经解码的字节数组。
  **/ 
  public static byte [] decode(String message,int offset) throws IOException
  	{String messageInALine = message;
  	 messageInALine = messageInALine.replaceAll("\r\n","");
  	 byte [] decodeByte = Base64.decode(messageInALine.getBytes(),offset);
  	 return decodeByte;
  	}
 /**
  *将指定字符串解码后返回。
  *@param messageByte 是要进行解码的字节数组。
  *@return 返回已经解码的字节数组。
  **/ 
 public static byte [] decode(byte [] messageByte) throws IOException
 	{int currentIndex=0,div=0,mod=0;
 	 byte tempByte=0,messageByteToInt=0;
 	 int messageLength = messageByte.length;
 	 int decodedLength = messageLength/4*3;
 	 if(messageByte[messageLength-2]=='=')
 		 decodedLength-=2;
 	 else
 	 if(messageByte[messageLength-1]=='=')
 		 decodedLength-=1;
 	 byte [] decodedByte = new byte[decodedLength];
 	 for (currentIndex=0;currentIndex<messageLength;currentIndex++)
 	 	{//通过加法来优化除法和取模的速度。
 	 	 //div = currentIndex/4;
 	 	 //mod = currentIndex%4;
 	 	 /*	 
 	 	 //轮询查找效率最差
 	  	 while(messageByteToInt<64 && messageByte[currentIndex]!=encodeDict[messageByteToInt])
 	 	 	{messageByteToInt++;
 	 	 	}
 	  	 */
 	 	 /*
 	 	 //选择分支，动态查找效率差
 	 	 switch(messageByte[currentIndex])
 	 	 	{case 'A':
 	 	 		messageByteToInt=0; break;
 	 	 	 case 'B':
 	 	 		messageByteToInt=1; break;
 	 	 	 case 'C':
 	 	 		messageByteToInt=2; break;
 	 	 	 case 'D':
 	 	 		messageByteToInt=3; break;
 	 	 	 case 'E':
 	 	 		messageByteToInt=4; break;
 	 	 	 case 'F':
 	 	 		messageByteToInt=5; break;
 	 	 	 case 'G':
 	 	 		messageByteToInt=6; break;
 	 	 	 case 'H':
 	 	 		messageByteToInt=7; break;
 	 	 	 case 'I':
 	 	 		messageByteToInt=8; break;
 	 	 	 case 'J':
 	 	 		messageByteToInt=9; break;
 	 	 	 case 'K':
 	 	 		messageByteToInt=10; break;
 	 	 	 case 'L':
 	 	 		messageByteToInt=11; break;
 	 	 	 case 'M':
 	 	 		messageByteToInt=12; break;
 	 	 	 case 'N':
 	 	 		messageByteToInt=13; break;
 	 	 	 case 'O':
 	 	 		messageByteToInt=14; break;
 	 	 	 case 'P':
 	 	 		messageByteToInt=15; break;
 	 	 	 case 'Q':
 	 	 		messageByteToInt=16; break;
 	 	 	 case 'R':
 	 	 		messageByteToInt=17; break;
 	 	 	 case 'S':
 	 	 		messageByteToInt=18; break;
 	 	 	 case 'T':
 	 	 		messageByteToInt=19; break;
 	 	 	 case 'U':
 	 	 		messageByteToInt=20; break;
 	 	 	 case 'V':
 	 	 		messageByteToInt=21; break;
 	 	 	 case 'W':
 	 	 		messageByteToInt=22; break;
 	 	 	 case 'X':
 	 	 		messageByteToInt=23; break;
 	 	 	 case 'Y':
 	 	 		messageByteToInt=24; break;
 	 	 	 case 'Z':
 	 	 		messageByteToInt=25; break;
 	 	 	 case 'a':
 	 	 		messageByteToInt=26; break;
 	 	 	 case 'b':
 	 	 		messageByteToInt=27; break;
 	 	 	 case 'c':
 	 	 		messageByteToInt=28; break;
 	 	 	 case 'd':
 	 	 		messageByteToInt=29; break;
 	 	 	 case 'e':
 	 	 		messageByteToInt=30; break;
 	 	 	 case 'f':
 	 	 		messageByteToInt=31; break;
 	 	 	 case 'g':
 	 	 		messageByteToInt=32; break;
 	 	 	 case 'h':
 	 	 		messageByteToInt=33; break;
 	 	 	 case 'i':
 	 	 		messageByteToInt=34; break;
 	 	 	 case 'j':
 	 	 		messageByteToInt=35; break;
 	 	 	 case 'k':
 	 	 		messageByteToInt=36; break;
 	 	 	 case 'l':
 	 	 		messageByteToInt=37; break;
 	 	 	 case 'm':
 	 	 		messageByteToInt=38; break;
 	 	 	 case 'n':
 	 	 		messageByteToInt=39; break;
 	 	 	 case 'o':
 	 	 		messageByteToInt=40; break;
 	 	 	 case 'p':
 	 	 		messageByteToInt=41; break;
 	 	 	 case 'q':
 	 	 		messageByteToInt=42; break;
 	 	 	 case 'r':
 	 	 		messageByteToInt=43; break;
 	 	 	 case 's':
 	 	 		messageByteToInt=44; break;
 	 	 	 case 't':
 	 	 		messageByteToInt=45; break;
 	 	 	 case 'u':
 	 	 		messageByteToInt=46; break;
 	 	 	 case 'v':
 	 	 		messageByteToInt=47; break;
 	 	 	 case 'w':
 	 	 		messageByteToInt=48; break;
 	 	 	 case 'x':
 	 	 		messageByteToInt=49; break;
 	 	 	 case 'y':
 	 	 		messageByteToInt=50; break;
 	 	 	 case 'z':
 	 	 		messageByteToInt=51; break;
 	 	 	 case '0':
 	 	 		messageByteToInt=52; break;
 	 	 	 case '1':
 	 	 		messageByteToInt=53; break;
 	 	 	 case '2':
 	 	 		messageByteToInt=54; break;
 	 	 	 case '3':
 	 	 		messageByteToInt=55; break;
 	 	 	 case '4':
 	 	 		messageByteToInt=56; break;
 	 	 	 case '5':
 	 	 		messageByteToInt=57; break;
 	 	 	 case '6':
 	 	 		messageByteToInt=58; break;
 	 	 	 case '7':
 	 	 		messageByteToInt=59; break;
 	 	 	 case '8':
 	 	 		messageByteToInt=60; break;
 	 	 	 case '9':
 	 	 		messageByteToInt=61; break;
 	 	 	 case '+':
 	 	 		messageByteToInt=62; break;
 	 	 	 case '/':
 	 	 		messageByteToInt=63; break;
 	 	 	 default:
 	 	 		messageByteToInt=64; break;
 	 	 	}
 	 	 */
 	 	 //静态数组随机访问，效率最好。
 	 	 messageByteToInt = decodeDict[messageByte[currentIndex]];
 	 	 if (messageByte[currentIndex]=='=')
 	 	 	break;
 	 	 if (messageByteToInt>=64)
 	 	 	{throw new IOException("需要解码字符串错误\nthe param is error");
 	 	 	}
 	 	 switch (mod)
 	 	 	{case 0:
 	 	 		tempByte = messageByteToInt;
 	 	 		mod++;
 	 	 		break;
 	 	 	 case 1:
 	 	 	 	//temp = (byte)(temp << 2);
 	 	 	 	tempByte = (byte)((tempByte << 2) + ((messageByteToInt&48)>>4));
 	 	 	 	decodedByte[div*3+mod-1] = tempByte;
 	 	 	 	tempByte = (byte)(messageByteToInt&15);
 	 	 		mod++;
 	 	 	 	break; 
 	 	 	 case 2:
 	 	 	 	//temp = (byte)(temp << 4);
 	 	 	 	tempByte = (byte)((tempByte << 4) + ((messageByteToInt&60)>>2));
 	 	 	 	decodedByte[div*3+mod-1] = tempByte;
 	 	 	 	tempByte = (byte)(messageByteToInt&3);
 	 	 		mod++;
 	 	 	 	break;
 	 	 	 case 3:
 	 	 	 	//temp = (byte)(temp << 6);
 	 	 	 	tempByte = (byte)((tempByte << 6) + messageByteToInt);
 	 	 	 	decodedByte[div*3+mod-1] = tempByte;
 	 	 	 	mod = 0;
 	 	 	 	div++;
 	 	 	 	break;
 	 	 	}
 	 	}
 	 return decodedByte;
 	}
 /**
  *将指定字符串解码后返回。
  *@param messageByte 是要进行解码的字节数组。
   *@param offset 字典偏移量,当此参数为0时是标准Base64解密，否则将其与64取模所得的值作为字典的起点。进行变异解密。
  *@return 返回已经解码的字节数组。
  **/ 
 public static byte [] decode(byte [] messageByte,int offset) throws IOException
 	{if(offset==0)
 		return Base64.decode(messageByte);
	 int currentIndex=0,div=0,mod=0;
 	 byte tempByte=0,messageByteToInt=0;
 	 int messageLength = messageByte.length;
 	 int decodedLength = messageLength/4*3;
 	 int currentOffset = offset%64;
 	 if(messageByte[messageLength-2]=='=')
 		 decodedLength-=2;
 	 else
 	 if(messageByte[messageLength-1]=='=')
 		 decodedLength-=1;
 	 byte [] decodedByte = new byte[decodedLength];
 	 for (currentIndex=0;currentIndex<messageLength;currentIndex++)
 	 	{//静态数组随机访问，效率最好。
 	 	 messageByteToInt = decodeDict[messageByte[currentIndex]];
 	 	 messageByteToInt -= currentOffset;
 	 	 messageByteToInt = (byte)(messageByteToInt<0?messageByteToInt+64:messageByteToInt);
 	 	 if (messageByte[currentIndex]=='=')
 	 	 	break;
 	 	 if (messageByteToInt>=64)
 	 	 	{throw new IOException("需要解码字符串错误\nthe param is error");
 	 	 	}
 	 	 switch (mod)
 	 	 	{case 0:
 	 	 		tempByte = messageByteToInt;
 	 	 		mod++;
 	 	 		break;
 	 	 	 case 1:
 	 	 	 	//temp = (byte)(temp << 2);
 	 	 	 	tempByte = (byte)((tempByte << 2) + ((messageByteToInt&48)>>4));
 	 	 	 	decodedByte[div*3+mod-1] = tempByte;
 	 	 	 	tempByte = (byte)(messageByteToInt&15);
 	 	 		mod++;
 	 	 	 	break; 
 	 	 	 case 2:
 	 	 	 	//temp = (byte)(temp << 4);
 	 	 	 	tempByte = (byte)((tempByte << 4) + ((messageByteToInt&60)>>2));
 	 	 	 	decodedByte[div*3+mod-1] = tempByte;
 	 	 	 	tempByte = (byte)(messageByteToInt&3);
 	 	 		mod++;
 	 	 	 	break;
 	 	 	 case 3:
 	 	 	 	//temp = (byte)(temp << 6);
 	 	 	 	tempByte = (byte)((tempByte << 6) + messageByteToInt);
 	 	 	 	decodedByte[div*3+mod-1] = tempByte;
 	 	 	 	mod = 0;
 	 	 	 	div++;
 	 	 	 	break;
 	 	 	}
 	 	}
 	 return decodedByte;
 	}
 /**
  *将一个输入流进行解码.适用于所有文件，通过流的available()方法获取流大小大于1M的采用硬盘缓存形式，否则用内存缓存。<br/>
  *文件流自动识别测试通过，其他流没有经过测试。
  *@param inputStream 是要进行解码的输入流。
  *@return 返回解码后的输入流。
  **/
 public static InputStream decode(InputStream inputStream) throws IOException
	{InputStream decodedInputStream = null;
	 if(inputStream.available()>tempFileLength)
		 decodedInputStream = Base64.decodeByTempFile(inputStream);
	 else
		 decodedInputStream = Base64.decodeByMemory(inputStream);
	 return decodedInputStream;
	}
 /**
  *将一个输入流进行解码.适用于所有文件，通过流的available()方法获取流大小大于1M的采用硬盘缓存形式，否则用内存缓存。<br/>
  *文件流自动识别测试通过，其他流没有经过测试。
  *@param inputStream 是要进行解码的输入流。
   *@param offset 字典偏移量,当此参数为0时是标准Base64解密，否则将其与64取模所得的值作为字典的起点。进行变异解密。
  *@return 返回解码后的输入流。
  **/
 public static InputStream decode(InputStream inputStream,int offset) throws IOException
	{InputStream decodedInputStream = null;
	 if(inputStream.available()>tempFileLength)
		 decodedInputStream = Base64.decodeByTempFile(inputStream,offset);
	 else
		 decodedInputStream = Base64.decodeByMemory(inputStream,offset);
	 return decodedInputStream;
	}
 /**
  *将一个输入流进行解码.只适用于小文件，大文件消耗资源太厉害容易引起JVM崩溃。但由于使用内存作为缓存效率较高。
  *@param inputStream 是要进行解码的输入流。
  *@return 返回解码后的输入流。
  **/
 private static InputStream decodeByMemory(InputStream inputStream) throws IOException
 	{ByteArrayOutputStream outputStreamToMemory = new ByteArrayOutputStream();
 	 int currentChar = -1;
 	 byte [] content = null;
 	 while((currentChar=inputStream.read())!=-1)
 	 	{//处理smtp协议中的base64加密换行情况
 		 if(currentChar!='\r' && currentChar!='\n')
 	 		outputStreamToMemory.write(currentChar); 	 	
 	 	}
 	 content = outputStreamToMemory.toByteArray();
 	 content = Base64.decode(content);
 	 ByteArrayInputStream inputStreamFromMemory = new ByteArrayInputStream(content);
 	 System.gc();
 	 return inputStreamFromMemory;
 	}
 /**
  *将一个输入流进行解码.只适用于小文件，大文件消耗资源太厉害容易引起JVM崩溃。但由于使用内存作为缓存效率较高。
  *@param inputStream 是要进行解码的输入流。
  *@param offset 字典偏移量,当此参数为0时是标准Base64解密，否则将其与64取模所得的值作为字典的起点。进行变异解密。
  *@return 返回解码后的输入流。
  **/
 private static InputStream decodeByMemory(InputStream inputStream,int offset) throws IOException
 	{ByteArrayOutputStream outputStreamToMemory = new ByteArrayOutputStream();
 	 int currentChar = -1;
 	 byte [] content = null;
 	 while((currentChar=inputStream.read())!=-1)
 	 	{//处理smtp协议中的base64加密换行情况
 		 if(currentChar!='\r' && currentChar!='\n')
 	 		outputStreamToMemory.write(currentChar); 	 	
 	 	}
 	 content = outputStreamToMemory.toByteArray();
 	 content = Base64.decode(content,offset);
 	 ByteArrayInputStream inputStreamFromMemory = new ByteArrayInputStream(content);
 	 System.gc();
 	 return inputStreamFromMemory;
 	}
 /**
  *将一个输入流进行解码.适用于大文件，但由于使用硬盘作为缓存效率较低。
  *@param inputStream 是要进行解码的输入流。
  *@return 返回解码后的输入流。
  **/
 private static InputStream decodeByTempFile(InputStream inputStream) throws IOException
 	{byte []content = new byte[4000];
 	 FileInputStream inputStreamFromTempFile = null;
 	 int length = -1;
 	 File tempFile = File.createTempFile(UUID.randomUUID().toString(), null);
 	 FileOutputStream outputStreamToTempFile = new FileOutputStream(tempFile);
 	 while((length=inputStream.read(content))!=-1)
 		 {byte []decodedContent = null;
 		  if(length==4000)
 			 decodedContent = Base64.decode(content);
 		  else
 			 {byte temp[] = new byte[length];
 			  for(int i=0;i<length;i++)
 				  temp[i] = content[i];
 			  decodedContent = Base64.decode(temp);
 			 }
 		  outputStreamToTempFile.write(decodedContent, 0, decodedContent.length);
 		  outputStreamToTempFile.flush();
 		 }
 	 outputStreamToTempFile.close();
 	 inputStreamFromTempFile = new FileInputStream(tempFile);
	 System.gc();
 	 return inputStreamFromTempFile;
 	}
 /**
  *将一个输入流进行解码.适用于大文件，但由于使用硬盘作为缓存效率较低。
  *@param inputStream 是要进行解码的输入流。
  *@param offset 字典偏移量,当此参数为0时是标准Base64解密，否则将其与64取模所得的值作为字典的起点。进行变异解密。
  *@return 返回解码后的输入流。
  **/
 private static InputStream decodeByTempFile(InputStream inputStream,int offset) throws IOException
 	{byte []content = new byte[4000];
 	 FileInputStream inputStreamFromTempFile = null;
 	 int length = -1;
 	 File tempFile = File.createTempFile(UUID.randomUUID().toString(), null);
 	 FileOutputStream outputStreamToTempFile = new FileOutputStream(tempFile);
 	 while((length=inputStream.read(content))!=-1)
 		 {byte []decodedContent = null;
 		  if(length==4000)
 			 decodedContent = Base64.decode(content,offset);
 		  else
 			 {byte temp[] = new byte[length];
 			  for(int i=0;i<length;i++)
 				  temp[i] = content[i];
 			  decodedContent = Base64.decode(temp,offset);
 			 }
 		  outputStreamToTempFile.write(decodedContent, 0, decodedContent.length);
 		  outputStreamToTempFile.flush();
 		 }
 	 outputStreamToTempFile.close();
 	 inputStreamFromTempFile = new FileInputStream(tempFile);
	 System.gc();
 	 return inputStreamFromTempFile;
 	}
 /**
  * 将一个输入流进行解码.适用于大文件，但由于使用硬盘作为缓存效率较低，不过比decodeByTempFile(InputStream)效率高。
  * @param inFile 是要进行编码的输入文件对象。
  * @param outFile 是进行编码后的输出文件对象。
  * @throws IOException 编码产生错误时抛出此异常。
  */
 private static void decodeToFile(File inFile,File outFile) throws IOException
 	{if(!inFile.isFile())
 		return;
	 if(outFile.getParentFile()!=null && !outFile.getParentFile().exists() && !outFile.getParentFile().mkdirs())
		return;
	 byte []content = new byte[3000];
 	 FileInputStream inputStream = new FileInputStream(inFile);
 	 int length = -1;
 	 FileOutputStream outputStreamToFile = new FileOutputStream(outFile);
 	 while((length=inputStream.read(content))!=-1)
 		 {byte []decodedContent = null;
 		  if(length==3000)
 			 decodedContent = Base64.decode(content);
 		  else
 			 {byte temp[] = new byte[length];
 			  for(int i=0;i<length;i++)
 				  temp[i] = content[i];
 			  decodedContent = Base64.decode(temp);
 			 }
 		  outputStreamToFile.write(decodedContent, 0, decodedContent.length);
 		  outputStreamToFile.flush();
 		 }
 	 outputStreamToFile.close();
 	 inputStream.close();
 	}
 /**
  * 将一个输入流进行解码.适用于大文件，但由于使用硬盘作为缓存效率较低，不过比decodeByTempFile(InputStream,int)效率高。
  * @param inFile 是要进行编码的输入文件对象。
  * @param outFile 是进行编码后的输出文件对象。
  * @param offset 字典偏移量,当此参数为0时是标准Base64加密，否则将其与64取模所得的值作为字典的起点。进行变异加密。
  * @throws IOException 编码产生错误时抛出此异常。
  */
 private static void decodeToFile(File inFile,File outFile,int offset) throws IOException
 	{if(!inFile.isFile())
 		return;
	 if(outFile.getParentFile()!=null && !outFile.getParentFile().exists() && !outFile.getParentFile().mkdirs())
		return;
	 byte []content = new byte[3000];
 	 FileInputStream inputStream = new FileInputStream(inFile);
 	 int length = -1;
 	 FileOutputStream outputStreamToFile = new FileOutputStream(outFile);
 	 while((length=inputStream.read(content))!=-1)
 		 {byte []decodedContent = null;
 		  if(length==3000)
 			 decodedContent = Base64.decode(content,offset);
 		  else
 			 {byte temp[] = new byte[length];
 			  for(int i=0;i<length;i++)
 				  temp[i] = content[i];
 			  decodedContent = Base64.decode(temp,offset);
 			 }
 		  outputStreamToFile.write(decodedContent, 0, decodedContent.length);
 		  outputStreamToFile.flush();
 		 }
 	 outputStreamToFile.close();
 	 inputStream.close();
 	}
 /**
  *将一个输入流进行解码.适用于所有文件，通过流的available()方法获取流大小大于1M的采用硬盘缓存形式，否则用内存缓存。<br/>
  *文件流自动识别测试通过，其他流没有经过测试。
  *@param inFileInputStream 是要进行解码的输入流。
  *@param outFileOutputStream 是进行解码后的输出流。
  **/
 public static void decode(InputStream inFileInputStream,OutputStream outFileOutputStream) throws IOException
 	{InputStream decodedInputStream = Base64.decode(inFileInputStream);
 	 byte [] temp = new byte[5000];
 	 int length = -1;
 	 if(decodedInputStream==null)
 		 return;
	 while((length=decodedInputStream.read(temp))!=-1)
	 	{outFileOutputStream.write(temp,0,length);
	 	}
	 outFileOutputStream.flush();
	 System.gc();
 	}
 /**
  *将一个输入文件进行解码.适用于所有文件，通过流的available()方法获取流大小大于1M的采用硬盘缓存形式，否则用内存缓存。<br/>
  *文件流自动识别测试通过，其他流没有经过测试。
  *@param inFile 是要进行解码的输入文件对象。
  *@param outFile 是进行解码后的输出文件对象。
  **/
 public static void decode(File inFile,File outFile) throws IOException
 	{if(!inFile.exists())
 		return;
 	 if(inFile.isFile())
 		Base64.decodeFromFile(inFile, outFile);
 	 else
 		Base64.decodeFromDirectory(inFile, outFile);
 	}
 /**
  *将一个输入文件进行解码.适用于所有文件，通过流的available()方法获取流大小大于1M的采用硬盘缓存形式，否则用内存缓存。<br/>
  *文件流自动识别测试通过，其他流没有经过测试。
  *@param inFileName 是要进行解码的输入文件路经。
  *@param outFileName 是进行解码后的输出文件路经。
  **/
 public static void decode(String inFileName,String outFileName) throws IOException
 	{File inFile = new File(inFileName);
 	 File outFile = new File(outFileName);
 	 Base64.decode(inFile,outFile);
 	}
 /**
  *将一个输入文件进行解码.适用于所有文件，通过流的available()方法获取流大小大于1M的采用硬盘缓存形式，否则用内存缓存。<br/>
  *文件流自动识别测试通过，其他流没有经过测试。
  *@param inFile 是要进行解码的输入文件对象。
  *@param outFile 是进行解码后的输出文件对象。
  **/
 private static void decodeFromFile(File inFile,File outFile) throws IOException
 	{if(!inFile.isFile())
 		return;
 	 if(!outFile.getParentFile().exists() && !outFile.getParentFile().mkdirs())
 		return;
 	 Base64.decodeToFile(inFile, outFile);
 	 /*
	 FileInputStream inFileInputStream = new FileInputStream(inFile);
 	 FileOutputStream outFileOutputStream = new FileOutputStream(outFile);
	 Base64.decode(inFileInputStream, outFileOutputStream);
	 inFileInputStream.close();
	 outFileOutputStream.close();
	 */
 	}
 /**
  *将一个输入文件夹进行解码.适用于所有文件，通过流的available()方法获取流大小大于1M的采用硬盘缓存形式，否则用内存缓存。<br/>
  *文件流自动识别测试通过，其他流没有经过测试。
  *@param inFile 是要进行解码的输入文件夹对象。
  *@param outFile 是进行解码后的输出文件夹对象。
  **/
 private static void decodeFromDirectory(File inFile,File outFile)
	{if(!inFile.isDirectory())
		return;
	 if(!outFile.exists())
	 	{if(!outFile.mkdirs())
	 		return;
	 	}
	 else
	 if(!outFile.isDirectory())
		return;
	 for(File currentFile:inFile.listFiles())
	 	{File outDirectory = new File(outFile,currentFile.getName());
		 if(currentFile.isDirectory())
			{if(outDirectory.mkdirs())
				 Base64.decodeFromDirectory(currentFile, outDirectory);
			}
		 else
			{try
			 	{Base64.decodeFromFile(currentFile, outDirectory);
			 	}
			 catch(IOException e)
			 	{if(outDirectory.exists())
 			 		outDirectory.delete();
				 System.err.println("Base64.decode "+currentFile.getAbsolutePath()+" to "+outDirectory.getAbsolutePath()+" error!\n"+e.getMessage());
			 	}
			}
	 	}
	}
 /**
  *将一个输入流进行解码.适用于所有文件，通过流的available()方法获取流大小大于1M的采用硬盘缓存形式，否则用内存缓存。<br/>
  *文件流自动识别测试通过，其他流没有经过测试。
  *@param inFileInputStream 是要进行解码的输入流。
  *@param outFileOutputStream 是进行解码后的输出流。
  *@param offset 字典偏移量,当此参数为0时是标准Base64解密，否则将其与64取模所得的值作为字典的起点。进行变异解密。
  **/
 public static void decode(InputStream inFileInputStream,OutputStream outFileOutputStream,int offset) throws IOException
 	{InputStream decodedInputStream = Base64.decode(inFileInputStream,offset);
 	 byte [] temp = new byte[5000];
 	 int length = -1;
 	 if(decodedInputStream==null)
 		 return;
	 while((length=decodedInputStream.read(temp))!=-1)
	 	{outFileOutputStream.write(temp,0,length);
	 	}
	 outFileOutputStream.flush();
	 System.gc();
 	}
 /**
  *将一个输入文件进行解码.适用于所有文件，通过流的available()方法获取流大小大于1M的采用硬盘缓存形式，否则用内存缓存。<br/>
  *文件流自动识别测试通过，其他流没有经过测试。
  *@param inFile 是要进行解码的输入文件对象。
  *@param outFile 是进行解码后的输出文件对象。
  *@param offset 字典偏移量,当此参数为0时是标准Base64解密，否则将其与64取模所得的值作为字典的起点。进行变异解密。
  **/
 public static void decode(File inFile,File outFile,int offset) throws IOException
 	{if(!inFile.exists())
 		return;
 	 if(inFile.isFile())
 		Base64.decodeFromFile(inFile, outFile, offset);
 	 else
 		Base64.decodeFromDirectory(inFile, outFile, offset);
 	}
 /**
  *将一个输入文件进行解码.适用于所有文件，通过流的available()方法获取流大小大于1M的采用硬盘缓存形式，否则用内存缓存。<br/>
  *文件流自动识别测试通过，其他流没有经过测试。
  *@param inFileName 是要进行解码的输入文件路经。
  *@param outFileName 是进行解码后的输出文件路经。
  *@param offset 字典偏移量,当此参数为0时是标准Base64解密，否则将其与64取模所得的值作为字典的起点。进行变异解密。
  **/
 public static void decode(String inFileName,String outFileName,int offset) throws IOException
 	{File inFile = new File(inFileName);
 	 File outFile = new File(outFileName);
 	 Base64.decode(inFile,outFile,offset);
 	}
 /**
  *将一个输入文件进行解码.适用于所有文件，通过流的available()方法获取流大小大于1M的采用硬盘缓存形式，否则用内存缓存。<br/>
  *文件流自动识别测试通过，其他流没有经过测试。
  *@param inFile 是要进行解码的输入文件对象。
  *@param outFile 是进行解码后的输出文件对象。
  *@param offset 字典偏移量,当此参数为0时是标准Base64解密，否则将其与64取模所得的值作为字典的起点。进行变异解密。
  **/
 private static void decodeFromFile(File inFile,File outFile,int offset) throws IOException
 	{if(!inFile.isFile())
 		return;
 	 if(outFile.getParentFile()!=null && !outFile.getParentFile().exists() && !outFile.getParentFile().mkdirs())
 		return;
 	 Base64.decodeToFile(inFile, outFile, offset);
 	 /*
	 FileInputStream inFileInputStream = new FileInputStream(inFile);
 	 FileOutputStream outFileOutputStream = new FileOutputStream(outFile);
	 Base64.decode(inFileInputStream, outFileOutputStream,offset);
	 inFileInputStream.close();
	 outFileOutputStream.close();
	 */
 	}
 /**
  *将一个输入文件夹进行解码.适用于所有文件，通过流的available()方法获取流大小大于1M的采用硬盘缓存形式，否则用内存缓存。<br/>
  *文件流自动识别测试通过，其他流没有经过测试。
  *@param inFile 是要进行解码的输入文件夹对象。
  *@param outFile 是进行解码后的输出文件夹对象。
  *@param offset 字典偏移量,当此参数为0时是标准Base64解密，否则将其与64取模所得的值作为字典的起点。进行变异解密。
  **/
 private static void decodeFromDirectory(File inFile,File outFile,int offset)
	{if(!inFile.isDirectory())
		return;
	 if(!outFile.exists())
	 	{if(!outFile.mkdirs())
	 		return;
	 	}
	 else
	 if(!outFile.isDirectory())
		return;
	 for(File currentFile:inFile.listFiles())
	 	{File outDirectory = new File(outFile,currentFile.getName());
		 if(currentFile.isDirectory())
			{if(outDirectory.mkdirs())
				 Base64.decodeFromDirectory(currentFile, outDirectory, offset);
			}
		 else
			{try
			 	{Base64.decodeFromFile(currentFile, outDirectory, offset);
			 	}
			 catch(IOException e)
			 	{if(outDirectory.exists())
 			 		outDirectory.delete();
				 System.err.println("Base64.decode "+currentFile.getAbsolutePath()+" to "+outDirectory.getAbsolutePath()+" error!\n"+e.getMessage());
			 	}
			}
	 	}
	}
 /**
  * 对文件或文件夹进行Base64编码、解码操作。通过文件选择器来选择文件或文件夹。
  * @param modal 选择文件时是否采用模式对话框，true为模式对话框,false为非模式对话框。
  */
 synchronized public static void showGUI(boolean modal)
 	{//Base64.offsetText.setText("0");
 	 //Base64.isEncode.setSelected(true);
	 Base64.inFileChooser.rescanCurrentDirectory();
	 Base64.outFileChooser.rescanCurrentDirectory();
 	 Base64.loadDialog.setModal(modal);
 	 Base64.loadDialog.setVisible(true);
 	}

 public static void main(String [] args) throws Exception
 	{if(args.length!=3 || args.length!=4)
		{System.out.println("用途:将文件或者文件夹下的文件进行Base64编码或解码。");
		 System.out.println("用法:encode|decode inFileName outFileName [offset]");
		 System.out.println("参数:");
		 System.out.println("\tencode 编码操作。");
		 System.out.println("\tdecode 解码操作。");
		 System.out.println("\tinFileName 要操作的文件或文件夹完整路径。");
		 System.out.println("\toutFileName 操作后产生的文件或文件夹完整路径。");
		 System.out.println("\toffset 进行变异编码解码操作时的变异值，此数值有效范围在0~63之间。当此值为0时为标准编码解码操作。");
	 	 return;
		}
	 boolean isEncode = args[0].toLowerCase().equalsIgnoreCase("encode");
	 String inFileName = args[1];
	 String outFileName = args[2];
	 int offset = 0;
	 try
	 	{offset = Integer.parseInt(args[3]);
	 	}
	 catch(Exception e)
	 	{System.err.println("错误:");
	 	 System.err.println("\toffset 变异值数值格式有误。");
	 	 System.err.println();
	 	 Base64.main(new String[0]);
	 	 return;
	 	}
	 if(isEncode)
	 	{if(offset==0)
	 		Base64.encode(inFileName,outFileName);
	 	 else
	 		Base64.encode(inFileName,outFileName,offset);
	 	}
	 else
	 	{if(offset==0)
	 		Base64.decode(inFileName,outFileName);
	 	 else
	 		Base64.decode(inFileName,outFileName,offset);
	 	}
	 /*
	 javax.swing.JFrame window = new javax.swing.JFrame("Base64编码或解码");
 	 JButton button = new JButton("选择文件或文件夹");
 	 button.addActionListener(
 			 new ActionListener()
 			 {public void actionPerformed(ActionEvent e)
 			 	{Base64.showGUI(true);
 			 	}
 			 }
 			 );
 	 window.setDefaultCloseOperation(javax.swing.JFrame.EXIT_ON_CLOSE);
 	 window.getContentPane().add(button);
 	 window.setSize(400,300);
 	 window.setVisible(true);
 	 */
	 /*
	 String t = "hew中国人hello";
 	 System.out.write(Base64.encode(t.getBytes(),46));
 	 System.out.println();
 	 System.out.write(Base64.decode(Base64.encode(t,5),5));
 	 System.out.println();
 	 */
 	 /*
 	 long start = System.currentTimeMillis();
 	 System.out.println("------------------file encode-------------------");
 	 FileInputStream fis = new FileInputStream("百万宝贝3.rmvb.jfenc");
 	 FileOutputStream fos = new FileOutputStream("百万宝贝3.rmvb.base64");
 	 InputStream is = Base64.encode(fis,5);
 	 System.out.println("------------------file encoded-------------------");
 	 System.out.println(System.currentTimeMillis()-start);
 	 int length = -1;
 	 byte []temp = new byte[5000];
 	 while((length=is.read(temp))!=-1)
 	 	{fos.write(temp,0,length);
 	 	 fos.flush();
 	 	}
 	 fos.close();
 	 System.out.println("------------------out encodeed-------------------");
 	 System.out.println(System.currentTimeMillis()-start);
 	 System.out.println("------------------out new method-----------------");
 	 Base64.encode("百万宝贝3.rmvb.jfenc", "百万宝贝3.rmvb.base64");
 	 System.out.println(System.currentTimeMillis()-start);
 	 */
 	 /*
 	 long start = System.currentTimeMillis();
 	 FileInputStream fis = new FileInputStream("百万宝贝3.rmvb.base64");
 	 FileOutputStream fos = new FileOutputStream("百万宝贝3.jfenc");
 	 System.out.println("------------------file decode-------------------");
 	 InputStream is = Base64.decode(fis,5);
 	 System.out.println("------------------file decoded-------------------");
 	 System.out.println(System.currentTimeMillis()-start);
 	 int length = -1;
 	 byte []temp = new byte[5000];
 	 length = -1;
 	 while((length=is.read(temp))!=-1)
 	 	{fos.write(temp,0,length);
 	 	}
 	 fos.close();
 	 System.out.println("------------------out decodeed-------------------");
 	 System.out.println(System.currentTimeMillis()-start);
 	 System.out.println();
 	 */
 	}
}
